package org.megha.blog.example.part17;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Solves a quadratic or a linear equation.
 * Additionally, it also shows how to create and use an Exception.
 * 
 * @author megha birmiwal
 */
public class EquationSolver {
	
	public static class NoSolutionException extends Exception {
		public NoSolutionException(String message) {
			super(message);
		}
	}

	/**
	 * Solves an equation of the form:
	 * <code>  c0 + c1 * x + c2 * x^2 = 0  </code>
	 * for <code>x</code> and returns the solutions.
	 * 
	 * @return the solutions; the the two solutions are the same, then only one is returned
	 * @throws NoSolutionException if there is no real solution for the given input
	 */
	public Collection<Double> solve(double c0, double c1, double c2) throws NoSolutionException {
		
		Set<Double> results = new HashSet<Double>();
		
		if (c2 ==0 && c1 ==0) {
			throw new NoSolutionException("cannot solve equation where coefficients are zero");
		}

		if (c2 == 0) {
			// linear equation
			results.add(-c0/c1);
			return results;
		}
		
		double factor = c1*c1 - 4*c2*c0;		
		if (factor < 0) {
			throw new NoSolutionException("no solution for inputs: " + c0 + ", " + c1 + ", " + c2);
		}
		
		// quadratic solution
		double srtfactor = Math.sqrt(factor);
		double solution1 = (-c1 + srtfactor)/(2*c2);
		double solution2 = (-c1 - srtfactor)/(2*c2);

		results.add(solution1);
		results.add(solution2);
		
		return results;
	}
	
	public static void main(String args[]) {
		if (args.length != 3) {
			System.out.println("please provide 3 numbers as arguments");
			return;
		}
		Collection<Double> solutions = null;
		EquationSolver solver = new EquationSolver();
		
		double cof0 = Double.parseDouble(args[0]);
		double cof1 = Double.parseDouble(args[1]);
		double cof2 = Double.parseDouble(args[2]);
		
		try {
			solutions = solver.solve(cof0, cof1, cof2);
		} catch (NoSolutionException e) {
			System.out.println("solution not possible: " + e.getMessage());
			return;
		} finally {
			// code in the finally block is executed after the try block completes or an exception block completes
			System.out.println("finally block!");
		}
		
		for (double solution : solutions) {
			System.out.println("solution: " + solution);
		}
	}
}
